#include "../src/polytomousrasch.c"

#include <assert.h>
#include <stdio.h>

typedef struct _PolytomousRaschTestDatum PolytomousRaschTestDatum;
struct _PolytomousRaschTestDatum 
{
  struct
    {
      unsigned int x;
      unsigned int z;
      float        beta;
      float        tau[5];
    }                           input;

  struct
    {
      float    p;
      float    dpdbeta;
      float    ddpddbeta;
      float    dpdtau[5];
    }                           output;
};

static void
test_polytomous_rasch (void)
{
  PolytomousRaschTestDatum data[] = 
{{{2, 1, 2.43188, {2.23959, 2.87959, 4.29279, 1.94046,  1.08165}}, {-7.63387, -3.05973, -0.0730163, {-2.31701, -2.4307,  4.64068e-7, 7.23947e-8, 3.26154e-8}}}, {{5, 2,  2.95456, {2.53133, 0.49753, 1.19261, 1.38763, 1.94629}}, {-0.69651,  0.07978, -0.0425159, {-0.00107449, -0.00129807, -0.0202354,  -0.225976, -1.48224}}}, {{5, 1,  4.10565, {1.34658, 4.19507, 2.86268, 2.25474,  4.0536}}, {-40.0927, -9.64536, -0.0188014, {-3.30832, -4.10564,  -4.10565, -4.10565, -4.10565}}}, {{3, 2,  1.08718, {2.53118, 1.1292, 2.72484, 1.7257,  4.68398}}, {-1.94487, -0.321635, -0.171598, {-0.23634, -0.368999,  -0.710892, 0.220813, 0.0113217}}}, {{3, 1,  3.69732, {0.485241, 3.84611, 0.391189, 1.75686,  4.40359}}, {-8.41122, -2.16992, -0.0312549, {-0.479579, -3.69636,  -3.69645, 0.0000500754, 1.7155e-10}}}, {{5, 3,  0.891548, {2.85986, 1.25933, 3.21098, 4.50391,  0.913571}}, {-1.0134,  0.566882, -0.527383, {-0.0434445, -0.0926706, -0.325037, -0.51756,  -0.567931}}}, {{3, 0,  2.15368, {1.8644, 0.30884, 3.05089, 4.89894,  2.8108}}, {-11.2781, -5.17172, -0.101265, {-2.0964, -2.13421,  -2.15366, 7.14592e-10, 1.67497e-12}}}, {{1, 0,  4.22166, {0.51971, 3.76975, 0.085966, 2.49596,  0.835734}}, {-2.29972, -0.46759, -0.0243712, {-3.79829,  8.79908e-8, 3.60991e-8, 9.85927e-13,  2.81194e-14}}}, {{0, 2,  0.0724271, {4.60072, 3.64986, 0.444545, 3.31557,  0.197136}}, {-1.60666,  2.48226, -2.06979, {0.0579014, 0.0458696, 0.0351929, 0.023243,  0.0123792}}}, {{3, 2,  2.75831, {2.58469, 2.05624, 1.98616, 3.2544,  1.67112}}, {-2.1787, -0.391511, -0.111102, {-1.76053, -2.11147,  -2.41198, 0.03412, 0.0243077}}}};

  for (unsigned int i = 0; i < sizeof (data) / sizeof (data[0]); ++i)
    {
      float dpdbeta;
      float ddpddbeta;
      float dpdtau[5];

#define taufunc(_k) data[i].input.tau[_k]
      float p = log_polytomous_rasch_dtau (data[i].input.x,
                                           data[i].input.z,
                                           data[i].input.beta,
                                           taufunc,
                                           5,
                                           dpdbeta,
                                           ddpddbeta,
                                           dpdtau);
#undef taufunc

      assert (      fabs (p - data[i].output.p) 
                 <= 1e-4 * (1 + fabs (p) + fabs (data[i].output.p))
              || (fprintf (stderr, "fail: %g != %g\n", p, data[i].output.p),
                  0));

      assert (      fabs (dpdbeta - data[i].output.dpdbeta) 
                 <= 1e-4 * (1 + fabs (dpdbeta) + fabs (data[i].output.dpdbeta))
              || (fprintf (stderr, "fail: %g != %g\n", dpdbeta, data[i].output.dpdbeta),
                  0));

      assert (      fabs (ddpddbeta - data[i].output.ddpddbeta) 
                 <= 1e-4 * (1 + fabs (ddpddbeta) + fabs (data[i].output.ddpddbeta))
              || (fprintf (stderr, "fail: %g != %g\n", ddpddbeta, data[i].output.ddpddbeta),
                  0));

      for (unsigned int k = 0; k < 5; ++k)
        {
          assert (      fabs (dpdtau[k] - data[i].output.dpdtau[k]) 
                     <= 1e-4 * (1 + fabs (dpdtau[k]) + fabs (data[i].output.dpdtau[k]))
                  || (fprintf (stderr, "fail: %g != %g\n", dpdtau[k], data[i].output.dpdtau[k]),
                      0));
        }
    }
}

int 
main (void)
{
  test_polytomous_rasch ();

  return 0;
}
